/* 
	vue3和vue2对观察者列表的存储上有所区别。vue2是vue实例中的data的每个key，都存储了一个被观察者
	列表，存在闭包中。而vue3是单独抽出来了一个targetMap，用来存储整个工程的被观察者。
	另外vue2是用Object.defineProperty实现的，是在现有的对象上做更改，给对象做代理的时候，先递归遍历了一遍对象，把所有的key值
	全部绑上代理。vue3是用proxy实现的，proxy会返回新的对象，vue3在此做的处理是先给对象的第一层做好代理，里面的数据
	等访问的时候再去处理
	问题：
	1.vue3这种把对对象（比第一层级深的层级）的代理放到get中，虽然有延迟加载的好处，但是这样相当于每次访问都要挂在proxy，
	会产生重复的挂载。不过由于proxy是挂在到对象上的，取值的时候顶多也就是取到对象，所以也就是取一次值的时候挂载一次，
	就还好，如果像vue2那样，使用Object.defineProperty，就不行了，挂载一个对象要把所有的key值全都串一遍，开销过大
	2.
	ref、reactive、computed、
 */

	function isObject(data) {
		return data && typeof data === 'object'
	}
	const targetMap = new Map()
	
	let activeEffect = null
	
	function gatherEffect(target, key) {
		let deps = targetMap.get(target)
		if (!deps) targetMap.set(target, deps = new Map())
		let dep = deps.get(key)
		if (!dep) deps.set(key, new Set())
		// 此处做了优化处理，由于回调函数每次都会把activeEffect挂上，所以要加判断
		if(!dep.has(activeEffect)) dep.add(activeEffect)
	}
	
	export function reactive(data) {
		return track(data)
	}
	
	function track(data) {
		if (!isObject(data)) return data
		return new Proxy(data, {
			get(target, key, receiver) {
				gatherEffect(target, key)
				const ret = Reflect.get(target,key,receiver)
				return isObject(ret) ? track(ret) : ret
			},
			set(target, key, value, reveiver) {
				Reflect.set(target, key, value, reveiver)
				triger(target, key, value)
			}
		})
	}
	
	function triger(target, key, newVal) {
		let listeners = targetMap.get(target) && targetMap.get(target).get(key)
		listeners.forEach(e => e.update(newVal))
	}
	
	
	function effect(fn, options) {
		let __effect = new ReactiveEffect(fn);
		options.lazy || __effect.run();
		return __effect;
	}
	
	class ReactiveEffect {
		constructor(fn) {
			this.fn = fn
		}
	
		run() {
			activeEffect = this
			this.fn()
		}
	}
	
	/* 
		1.vue2中的watch类，执行的时候并未执行回调函数，而是采用的直接取值的方式，并且把值存在了实例中，用来
		和后面的新值做对比，只有值变了，才去更新
		2.vue3中的effect
	 */